package com.sailors.common.task.provider.domian.model.entity;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.sailors.common.task.provider.application.event.publisher.FileTaskEventPublisher;
import com.sailors.common.task.provider.domian.model.identity.TaskIdentity;
import com.sailors.common.task.provider.domian.model.val.TaskProValueObj;
import com.sailors.common.task.provider.faced.model.dto.execute.FileTaskFailedExecuteDto;
import com.sailors.common.task.provider.faced.model.enums.TaskAsyncEnum;
import com.sailors.common.task.provider.faced.model.enums.TaskStatusEnum;
import com.sailors.common.task.provider.infra.design.common.exception.BussinessException;
import com.sailors.common.task.provider.infra.design.ddd.Entity;
import com.sailors.common.task.provider.infra.repository.IFileTaskLogRepository;
import com.sailors.common.task.provider.infra.repository.ITaskProLogRepository;
import com.sailors.common.task.provider.infra.repository.convert.FileTaskConver;
import com.sailors.common.task.provider.infra.repository.model.FileTaskLogPo;
import lombok.AccessLevel;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * Task entity
 *
 * @description: 通用任务领域对象
 * @author: cyj
 * @date 2022 -11-22 15:50:55
 */
@Data
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@Slf4j
public class FileTaskEntity extends Entity<TaskIdentity> {
    /**
     * 基本属性
     */
    private FileTaskEntityCommonProperty commonProperty;
    /**
     * 进度值对象
     */
    private List<TaskProValueObj> taskProValueObjs;

    /**
     * 仓储对象
     */
    private IFileTaskLogRepository taskLogRepository;

    /**
     * 仓储对象
     */
    private ITaskProLogRepository taskProLogRepository;

    /************************ 领域对象方法 ***********************************/
    /**
     * 任务是否完成
     * @return
     */
    public boolean isTaskfinish() {
        if (TaskStatusEnum.SUCCESS.getCode().equals(commonProperty.getStatus()) || TaskStatusEnum.FAILED.getCode().equals(commonProperty.getStatus())) {
            return true;
        }
        if (CollectionUtils.isEmpty(taskProValueObjs)) {
            return false;
        }
        return taskProValueObjs.stream().filter(taskProValueObj -> 100 == taskProValueObj.getProcess().intValue()).count() > 0;
    }

    /**
     * 任务是否失败
     * @return
     */
    public boolean isFailed() {
        return null != commonProperty.getStatus() && TaskStatusEnum.FAILED.getCode().equals(commonProperty.getStatus());
    }

    /**
     * 保存进度
     */
    public void saveProcess(TaskProValueObj taskProValueObj) {
        if (!isFailed()) {
            this.taskProLogRepository.save(taskProValueObj.getTaskId(), taskProValueObj.getProcess(), taskProValueObj.getCreateBy());
            // 加到领域值对象
            this.taskProValueObjs.add(taskProValueObj);
            // 进度已达100，则更新状态
            if (isTaskfinish()) {
                this.commonProperty.setStatus(TaskStatusEnum.SUCCESS.getCode());
                this.commonProperty.setOverTime(new Date());
                this.updateCommon();
            }
        }
    }

    /**
     * 更新基本信息
     */
    public void updateCommon() {
        taskLogRepository.updateById(FileTaskConver.entity2po(this));
    }

    /**
     * 更新任务失败
     * @param fileTaskFailedExecuteDto
     */
    public void updateFailed(FileTaskFailedExecuteDto fileTaskFailedExecuteDto) {
        // 进度也改成100
        this.saveProcess(new TaskProValueObj(identify.getId(), new BigDecimal(100), "system"));
        commonProperty.setStatus(TaskStatusEnum.FAILED.getCode());
        commonProperty.setOverTime(new Date());
        commonProperty.setReason(fileTaskFailedExecuteDto.getReason());
        commonProperty.setReasonUrl(fileTaskFailedExecuteDto.getReasonUrl());
        commonProperty.setSuccessFileUrl(fileTaskFailedExecuteDto.getSuccessFileUrl());
        updateCommon();
    }

    /**
     * 延时失败
     */
    public void delayedFailed() {
        if (TaskStatusEnum.PROCESS.getCode().equals(commonProperty.getStatus())) {
            // 进度也改成100
            this.saveProcess(new TaskProValueObj(identify.getId(), new BigDecimal(100), "system"));
            commonProperty.setStatus(TaskStatusEnum.FAILED.getCode());
            commonProperty.setOverTime(new Date());
            commonProperty.setReason("任务长时间未回传结果,自动终止！");
            updateCommon();
            log.info("任务长时间未回传结果,自动终止！ {}", identify.getId());
        }
    }

    /**
     * 创建新任务
     */
    public void createNewCommon() {
        if (null != getTaskLogRepository().getById(identify.getId())) {
            throw new BussinessException("领域对象已创建不能重复创建");
        }
        // 如果是异步步的不操作状态
        if (TaskAsyncEnum.YES.getCode().equals(commonProperty.getAsync())) {
            commonProperty.setStatus(null);
        }
        FileTaskLogPo fileTaskLogPo = FileTaskConver.entity2po(this);
        fileTaskLogPo.setCreateTime(new Date());
        taskLogRepository.saveCommon(fileTaskLogPo);
        // 默认保存一个0进度
        if (!isFailed()) {
            this.saveProcess(new TaskProValueObj(identify.getId(), TaskAsyncEnum.YES.getCode().equals(commonProperty.getAsync())
                    ? BigDecimal.ZERO : new BigDecimal(100), commonProperty.getCreateBy()));
        }
        // 推送创建事件
        FileTaskEventPublisher.pushEvent(this);
    }

}
